﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace StephenEssential
{
    public struct Point : IEquatable<Point>
    {
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj is Point && Equals((Point) obj);
        }

        public bool Equals(int x, int y)
        {
            return X == x && Y == y;
        }


        public override int GetHashCode()
        {
            unchecked
            {
                return (X*397) ^ Y;
            }
        }

        public readonly int X;
        public readonly int Y;
        public static readonly Point Empty = new Point(0, 0);

        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
        public Point(int x) : this(x, x) { }
        public Point this[int xm, int ym]
        {
            get {return new Point(xm + X, ym + Y);}
        }

        public bool Equals(Point other)
        {
            return X == other.X && Y == other.Y;
        }
        public Point Row()
        {
            return new Point(X, 0);
        }
        public Point Col()
        {
            return new Point(0, Y);
        }
        public static bool operator ==(Point a, Point b)
        {
            return a.Equals(b);
        }

        public static bool operator !=(Point a, Point b)
        {
            return !(a == b);
        }
        public static Point operator +(Point a, Point b)
        {
            return new Point(a.X + b.X, a.Y + b.Y);
        }
        public static bool operator >(Point a, Point b)
        {
            return a.X > b.X && a.Y > b.Y;
        }
        public static bool operator <(Point a, Point b)
        {
            return a.X < b.X && a.Y < b.Y;
        }
        public static bool operator >=(Point a, Point b)
        {
            return a.X >= b.X && a.Y >= b.Y;
        }

        public static bool operator <=(Point a, Point b)
        {
            return a.X <= b.X && a.Y <= b.Y;
        }

        public static Point operator +(Point a, string b)
        {
            var matchResult = new Regex(@"(-?[0-9]+),(-?[0-9]+)").Match(b);
            return new Point(int.Parse(matchResult.Groups[0].Value), int.Parse(matchResult.Groups[1].Value)) + a;
        }
        public static Point operator -(Point a, Point b)
        {
            return new Point(a.X - b.X, a.Y - b.Y);
        }
        public static Point operator *(Point p, double d)
        {
            return new Point((int) (p.X*d), (int) (p.Y*d));
        }
        public static Point operator *(Point a, Point b)
        {
            return new Point(a.X * b.X, a.Y * b.Y);
        }
        public static Point operator /(Point a, Point b)
        {
            return new Point(a.X/b.X, a.Y/b.Y);
        }
        public static Point operator /(Point p, int a)
        {
            return new Point(p.X/a, p.Y/a);
        }
        public override string ToString()
        {
            return string.Format("({0}, {1})", X, Y);
        }

        public static Point operator -(Point a, int b)
        {
            return new Point(a.X - b, a.Y - b);
        }
        public IList<Point> GetFourNeibours()
        {
            var points = new[] {new Point(-1, 0), new Point(1, 0), new Point(0, 1), new Point(0, -1)};
            var tmp = this;
            return new Point[4].Pipe(arr => 4.Loop(i => arr[i] = tmp + points[i]));
        }
        public IList<Point> GetEightNeibors()
        {
            var nakedNeibors = new Bitmap<Point>(3, 3, (x, y) => new Point(x - 1, y - 1)).ToList();
            nakedNeibors.RemoveAt(4);
            var tmpThis = this;
            return nakedNeibors.Select(p => p + tmpThis);
        } 
    }
}
